package com.yokead.service.nginxlog;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.JsonMessage;
import cn.simplifydb.database.base.BaseRead;
import cn.simplifydb.database.run.read.Select;
import cn.simplifydb.database.run.read.SelectPage;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yokead.nginxlog.entity.Nginx_Log_2019;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * nginx日志分析service
 *
 * @author yangheng
 */
@Service
public class StatisticsService {

    @Resource
    private NginxLog2019Service nginxLog2019Service;

    /**
     * 一天的秒数
     */
    private static final long DAY_SECONDS = TimeUnit.DAYS.toSeconds(1);

    private JSONObject generateRootResult(long startTime, long endTime) {
        DateField dateField = (endTime - startTime) <= DAY_SECONDS ? DateField.HOUR_OF_DAY : DateField.DAY_OF_MONTH;
        List<DateTime> dateTimes = DateUtil.rangeToList(DateUtil.beginOfDay(new DateTime(startTime * 1000)), DateUtil.endOfDay(new DateTime(endTime * 1000)), dateField);
        if (CollUtil.isEmpty(dateTimes)) {
            return null;
        }
        return dateTimes.stream().collect(JSONObject::new, (parent, item) -> {
            String time;
            if (DateField.HOUR_OF_DAY == dateField) {
                time = DateUtil.format(item, "HH:00");
            } else {
                time = DateUtil.formatDate(item);
            }
            JSONObject object = new JSONObject();
            object.put("count", 0);
            object.put("time", time);
            parent.put(time, object);
        }, JSONObject::putAll);


    }

    private String getSqlFromTime(long startTime, long endTime) {
        String format = (endTime - startTime) <= DAY_SECONDS ? "%H:00" : "%Y-%m-%d";
        return StrUtil.format(" from_unixtime(time, '{}') AS timeTemp", format);
    }


    /**
     * 图表数据
     *
     * @param host      域名
     * @param search    搜索条件
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return String
     */
    public String chats(String host, String search, Long startTime, Long endTime) {
        JSONArray array = chatsBuild(host, search, startTime, endTime);
        return JsonMessage.getString(200, "", array);
    }


    private JSONArray chatsBuild(String host, String search, Long startTime, Long endTime) {
        JSONObject rootResult = generateRootResult(startTime, endTime);
        if (CollUtil.isEmpty(rootResult)) {
            return null;
        }
        JSONArray array = queryDb(host, search, startTime, endTime);
        if (CollUtil.isNotEmpty(array)) {
            for (int i = 0; i < array.size(); i++) {
                JSONObject item = array.getJSONObject(i);
                String time = item.getString("timeTemp");
                int count = item.getIntValue("count");
                JSONObject rootItem = rootResult.getJSONObject(time);
                if (CollUtil.isNotEmpty(rootItem)) {
                    rootItem.put("count", count);
                }
            }
        }
        return rootResult.values().stream().sorted(Comparator.comparing(item -> ((JSONObject) item).getString("time"))).collect(Collectors.toCollection(JSONArray::new));
    }


    private JSONArray queryDb(String host, String search, long startTime, long endTime) {
        String searchCondition = buildSearch(host, search, startTime, endTime);
        String time = getSqlFromTime(startTime, endTime);
        Select<?> select = nginxLog2019Service.generateSelect(BaseRead.Result.JsonArray, Nginx_Log_2019.class);
        select.setColumns("count(1) as count", time);
        select.where(searchCondition);
        select.groupBy("timeTemp");
        return select.run();
    }


    private String buildSearch(String host, String search, long startTime, long endTime) {
        StringBuilder searchCondition = new StringBuilder(StrUtil.format("domain = '{}' and  time >{} and time <{} ", host, startTime, endTime));
        if (StrUtil.isNotEmpty(search)) {
            searchCondition.append(" and (");
            searchCondition.append(StrUtil.format(" ip ={}", search));
            searchCondition.append(StrUtil.format(" or xip ={}", search));
            searchCondition.append(StrUtil.format(" or type ={}", search));
            searchCondition.append(StrUtil.format(" or domain like '%{}%'", search));
            searchCondition.append(StrUtil.format(" or status ={}", search));
            searchCondition.append(StrUtil.format(" or referer like '%{}%'", search));
            searchCondition.append(StrUtil.format(" or url like '%{}%' ", search));
            searchCondition.append(" )");
        }
        return searchCondition.toString();
    }

    /**
     * 分页表格数据
     *
     * @param host      域名
     * @param search    搜索条件
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param page      第几页
     * @param limit     一页几行
     * @return String
     */
    public String tableData(String host, String search, long startTime, long endTime, int page, int limit) {
        String searchCondition = buildSearch(host, search, startTime, endTime);
        SelectPage<?> selectPage = nginxLog2019Service.generateSelectPage(page, limit, Nginx_Log_2019.class);
        selectPage.setColumns("id", "ip", "xip", "time", "type","url", "status", "referer");
        selectPage.where(searchCondition);
        JSONObject result = selectPage.run();
        JSONArray results = result.getJSONArray("results");
        JSONObject object = JsonMessage.toJson(0, "", results);
        object.put("count", result.getIntValue("totalRecord"));
        Select<?> select = nginxLog2019Service.generateSelect(BaseRead.Result.JsonObject, Nginx_Log_2019.class);
        select.setColumns("count(1)");
        Object run = select.run();

        return object.toJSONString();


    }
}
